<?php
/**
 * Created by PhpStorm.
 * User: 牛赞赞
 * Date: 2020/12/31
 * Time: 10:31
 */

namespace App\Game\Logic;


use App\Game\Conf\MainCmd;
use App\Game\Conf\SubCmd;
use App\Game\Core\AStrategy;
use App\Game\Core\Packet;
use App\Task\GameSyncTask;
use App\Task\OutRobotTask;

class Calculate extends AStrategy
{
    /**
     * 游戏等待准备
     */
    public function exec()
    {
        $game_conf = config('game');
        $account = $this->_params['userinfo']['account'];
        $serv = server();
        $user_room_map_key = sprintf($game_conf['user_room'],$account);
        $room_no = redis()->get($user_room_map_key);
        $game_conf = config('game');
        //游戏进度：0.加入游戏阶段 1.准备阶段 2.换牌阶段 3.定缺阶段 4.出牌阶段 5.摸牌阶段 6.结算阶段
        $room_progress_key = sprintf($game_conf['user_room_progress'], $room_no);

        $fds = $this->getOtherFdsByRoomNo($room_no);// 当前房间所有连接
        $game_conf = $this->game_conf;
        if (empty($room_no)) {
            $msg = ['status' => 1, 'info' => '房间号不存在'];
            return $this->resp($msg);
        }
        $room_data_key = sprintf($game_conf['user_room_data'], $room_no);
        if (redis()->exists($room_data_key)) {

            $room_data = redis()->hGetAll($room_data_key);

            $uinfo_arr = $room_data['uinfo'];

            //重置对应游戏数据
            // 设置游戏结束状态
            $this->updateRoomData($room_no, ['is_game_over' => 1]);

            // 清除出牌计时器
            $this->cleanLoop($game_conf, $room_no);


            // 清除room_data
            $this->cleanRoomData($room_no);

            // 检查房间用户在线状态
            // 机器人或不在线用户
            $uids = $this->checkUserStatus($room_no);
            if (!empty($uids)) {
                $this->kickOutUsers($uids, $room_no, $fds);
            } else {
                // 都在线且都是真人玩家
                $this->cleanRoomPrepare($room_no);// 清除准备状态
            }
            // 清除房间换牌信息
            $this->cleanRoomChange($room_no);
            // 清除房间定缺信息
            $this->cleanRoomColor($room_no);
            // 更新游戏进度为结算
            redis()->set($room_progress_key, 6);


            //全员发送结算通知
            foreach ($fds as $fdv) {
                $user_info_key = sprintf($game_conf['user_info_key'], $fdv);
                $uinfo = redis()->get($user_info_key);
                $user_room_info = Packet::packFormat('OK', 0, ['score' => $uinfo_arr[$uinfo['account']]]);
                $return_data = Packet::packEncode($user_room_info, MainCmd::CMD_SYS,
                    SubCmd::SUB_GAME_CACULAR_RESP);
                //获取客户端信息
                $client_info = $serv->getClientInfo($fdv);
                $client[$fdv] = $client_info;
                if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                    $serv->push($fdv, $return_data, WEBSOCKET_OPCODE_BINARY);
                }
            }
        }

    }

    /**
     * 踢出不在线玩家并广播,加入机器人计时
     * @param $room_no
     * @return array
     */
    protected function checkUserStatus($room_no)
    {
        $game_conf = config('game');
        $redis = redis();
        $room_wait_key = sprintf($game_conf['user_room_wait'], $room_no);
        $game_conf['user_room_status'];
        if ($redis->exists($room_wait_key)) {
            $user_ids = json_decode($redis->get($room_wait_key), true);
            $out_uid = [];
            foreach ($user_ids as $v) {
                $status = $redis->hGet($game_conf['user_room_status'], (string)$v);
                //var_dump('玩家',$v,'状态',$status);
                if ($status != 1) {
                    $out_uid[] = $v;
                }
            }
            return $out_uid;
        } else {
            return [];
        }
    }

    /**
     * 踢出用户
     * @param $uids
     * @param $room_no
     * @param $fds
     */
    protected function kickOutUsers($uids, $room_no, $fds)
    {
        $game_conf = config('game');
        $robot_conf = config('robot');
        $redis = redis();
        $room_wait_key = sprintf($game_conf['user_room_wait'], $room_no);
        $room_chair_key = sprintf($game_conf['user_room_chair'], $room_no);
        $room_prepare_key = sprintf($game_conf['user_room_prepare'], $room_no);
        $room_total_key = sprintf($game_conf['user_room_total'], $room_no);
        $room_robotLoop_key = sprintf($robot_conf['user_room_robot'], $room_no);
        if (count($uids) >= 4) {
            // 全部踢出房间，世界广播
            $redis->del($room_wait_key);
            $redis->del($room_chair_key);
            $redis->del($room_prepare_key);
            $redis->del($room_robotLoop_key);
            $redis->sRem($room_total_key, (string)$room_no);
            foreach ($uids as $v) {
                $map_key = sprintf($game_conf['user_room'], $v);
                $redis->del($map_key);
            }
            $this->worldBroadcast();
        } else {
            $robots = []; // 机器人
            $players = []; // 玩家
            foreach ($uids as $v) {
                if (in_array($v, $robot_conf['robots'])) {
                    $robots[] = $v;
                } else {
                    $players[] = $v;
                }
            }
            // 掉线玩家踢出等待房间
            if ($redis->exists($room_wait_key) && !empty($players)) {
                $wait_total = json_decode($redis->get($room_wait_key), true);
                $wait = array_values(array_diff($wait_total, $players));
                $redis->set($room_wait_key, json_encode($wait));
            }
            // 清除准备状态,机器人保留
            if ($redis->exists($room_prepare_key)) {
                if (!empty($robots)) {
                    $redis->set($room_prepare_key, json_encode($robots));
                } else {
                    $redis->del($room_prepare_key);
                }
            }
            // 清除掉线玩家map
            if (!empty($players)) {
                foreach ($players as $v) {
                    $map_key = sprintf($game_conf['user_room'], $v);
                    $redis->del($map_key);
                }
            }
            // 清除掉线玩家座位号
            if ($redis->exists($room_chair_key) && !empty($players)) {
                $chair_total = json_decode($redis->get($room_chair_key), true);
                foreach ($players as $v) {
                    if (isset($chair_total[$v])) {
                        $chair_id = $chair_total[$v];
                        unset($chair_total[$v]);
                        $this->roomBroadcast($chair_id, $fds);
                    }
                }
                $redis->set($room_chair_key, json_encode($chair_total));
            }
            $this->worldBroadcast();

            // 计时清除机器人
//            if(!empty($robots)){
//                $robot_out_key = sprintf($robot_conf['user_room_outRobot'],$room_no);
//                foreach ($robots as $v){
//                    $redis->sAdd($robot_out_key,$v);
//                }
//                // 投递踢出机器人计时器
//                $task = container()->get(OutRobotTask::class);
//                $task->outRobot($robots,$room_no);
//            }
        }
    }

    /**
     * 清除机器人计数
     * @param $room_no
     */
    protected
    function cleanRobotLoop($room_no)
    {
        $robot_conf = config('robot');
        $robot_loop_key = sprintf($robot_conf['user_room_robot'], $room_no);
        if (redis()->exists($robot_loop_key)) {
            redis()->del($robot_loop_key);
        }
    }

    /**
     * 房间广播
     * @param $serv
     * @param $fds
     * @param $data
     */
    protected
    function roomBroadcast($serv, $fds, $data)
    {
        $user_room_info = Packet::packFormat('OK', 0, $data);
        $return_data = Packet::packEncode($user_room_info, MainCmd::CMD_SYS, SubCmd::SUB_GAME_CACULAR_RESP);
        foreach ($fds as $fd) {
            //获取客户端信息
            $client_info = $serv->getClientInfo($fd);
            $client[$fd] = $client_info;
            if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                $serv->push($fd, $return_data, WEBSOCKET_OPCODE_BINARY);
            }
        }
    }

    protected function resp($msg)
    {
        $fd = $this->_params['userinfo']['fd'];
        $serv = $this->_params['serv'];
        $data = Packet::packFormat('ERROR', 0, $msg);
        $return_data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_CACULAR_RESP);
//        //获取客户端信息
//        $client_info = $serv->getClientInfo($fd);
//        $client[$fd] = $client_info;
//        if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
            $serv->push($fd, $return_data, WEBSOCKET_OPCODE_BINARY);
//        }
    }
}